/******************************************************************************
*  COPYRIGHT MorningCore CO.,LTD
******************************************************************************/

/*****************************************************************
 * FileName::    ZCDFT.c
 * version::     V2.0.0
 * Purpose:      prime number length DFT of ZC sequence
 * Authors:      shanshan, 2009-09-01
 * Notes:        None
 ******************************************************************/

/******************************************************************************
*  HISTORY OF CHANGES
*   <Date>          <Author>        <Version>       <DESCRIPTION>
*   2009-09-01      shanshan        V1.0.0           original
*   2010-04-01      shanshan        V2.0.0           table to taylor for ZC seq
******************************************************************************/

/******************************************************************************
*  INCLUDE FILES
******************************************************************************/


#include "ZCDFT.h"

/*----------- function definition-----------------------------------*/
/*****************************************************************************
* Function: ZCDFT()
* Purpose:  This function performs DFT of prime number length sequence using
*           the algorithm in "Efficient computation of DFT of Zadoff-Chu sequences".
*
* Relation:
            Calls       : ....
            Called by   : PRACH_DFT()
* Params:
*   <Name>                  <Type>      <In/Out>    <Description>
*   DFT_Size                int16       In          DFT size i.e. input sequence length
*   RootSeqParam            int         In          Sequence index
*   PRACH_CyclicShiftParam  int         In          Cv value for cyclic shift
*   BitWidth                int8        In          processing bit width
*   DataIp[]                cmplx_frN   In          input sequence data
*   DataOp[]                cmplx_frN   Out         output of DFT
* Return:  void
* Note:    <the limitations to use this function or other comments>
*******************************************************************************/
#define PI 3.141592653589793
void ZCDFT
(
    stULParamTable *SimParam,
    cmplx_t       DataIp[],                // input sequence data
    cmplx_t       DataOp[]                 // output
)
{
    /*variables definition*/
    int i; // loop index
    cmplx_t   X_RA;   // X(0)
    int16 Inv_RootSeqParam; // Inverse_u*u = 1 mod N
    cmplx_t   *x_RA_Seq;    // x_RA = conj(x(Inverse_u*k))
    cmplx_t   *X_RA_Seq;    // X_RA = x_RA * X(0)
    cmplx_t   *W_RA_Seq;    // DFT[x(n+Cv)R(N)] = X(k) * W(-n*Cv)
    //cmplx_frN Round;
    cmplx_t   Temp1;
    int16     SeqIdx1;      // SeqIdx for looking up Table
    long      a;

    /*Init*/
    //Set_bit_width(BitWidth);

    /*Function body*/
    // calc X(0)
    X_RA.re = 0;
    X_RA.im = 0;
    Temp1.re = (double)X_RA.re;
    Temp1.im = (double)X_RA.im;

    for (i = 0; i < SimParam->L_RA; i++)
    {
        X_RA.re = X_RA.re + DataIp[i].re;
        X_RA.im = X_RA.im + DataIp[i].im;
    }
    // Inverse_u
    Inv_RootSeqParam = InverseCal(SimParam->L_RA, SimParam->PRACH_ZC_u);

    x_RA_Seq = (cmplx_t *)malloc(sizeof(cmplx_t) * SimParam->L_RA);
    X_RA_Seq = (cmplx_t *)malloc(sizeof(cmplx_t) * SimParam->L_RA);
    W_RA_Seq = (cmplx_t *)malloc(sizeof(cmplx_t) * SimParam->L_RA);

    //DFT
    for (i = 0; i < SimParam->L_RA; i++)
    {
        //a = PI*SimParam->PRACH_ZC_u*(Inv_RootSeqParam*i)*(Inv_RootSeqParam*i+1)/SimParam->L_RA;
        //x_RA_Seq[i].re = (double)cos(a);
        //x_RA_Seq[i].im = (double)sin(a);
        a = SimParam->PRACH_ZC_u * ((((Inv_RootSeqParam * i) % (2 * SimParam->L_RA)) * ((Inv_RootSeqParam * i + 1) % (2 * SimParam->L_RA))) % (2 * SimParam->L_RA));
        SeqIdx1 = (int16)(a % (2 * SimParam->L_RA));
        x_RA_Seq[i].re = (double)cos(PI * SeqIdx1 / SimParam->L_RA);
        x_RA_Seq[i].im = (double)sin(PI * SeqIdx1 / SimParam->L_RA);

        // X(k) = x_RA * X(0)
        X_RA_Seq[i].re = x_RA_Seq[i].re * X_RA.re - x_RA_Seq[i].im * X_RA.im;
        X_RA_Seq[i].im = x_RA_Seq[i].re * X_RA.im + x_RA_Seq[i].im * X_RA.re;

        // W(n) = exp{j*2*PI*n*Cv/N}
        W_RA_Seq[i].re = (double)cos(2 * PI * i * SimParam->PRACH_ZC_Cv / SimParam->L_RA);
        W_RA_Seq[i].im = (double)sin(2 * PI * i * SimParam->PRACH_ZC_Cv / SimParam->L_RA);

        // Out = X(k) * W
        DataOp[i].re = X_RA_Seq[i].re * W_RA_Seq[i].re - X_RA_Seq[i].im * W_RA_Seq[i].im;
        DataOp[i].im = X_RA_Seq[i].re * W_RA_Seq[i].im + X_RA_Seq[i].im * W_RA_Seq[i].re;
    }
    free(x_RA_Seq);
    free(X_RA_Seq);
    free(W_RA_Seq);
}

/*----------- function definition-----------------------------------*/
/*****************************************************************************
* Function: InverseCal()
* Purpose:  This function calculate the inverse of u
*
* Relation:
Calls       : ....
Called by   : ZCDFT()
* Params:
*   <Name>              <Type>      <In/Out>    <Description>
    RootSeqLen          int16       In          the length of ZC sequence
    u                   int16       In          Sequence index
* Return:  void
* Note:    <no>
*******************************************************************************/
int16 InverseCal(
    int16  RootSeqLen,
    int16  u
)
{
    int16 InverseN = 1;
    while (((u * InverseN) % RootSeqLen) != 1)
    {
        InverseN++;
    }
    return InverseN;
}

